/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simplepushserver;

import java.awt.Desktop;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JOptionPane;
import simplepushserver.file.Folder;
import simplepushserver.filesend.FileDownloader;
import simplepushserver.gui.NoneModalPopup;
import simplepushserver.gui.Notifier;
import simplepushserver.gui.ProgressListener;
import simplepushserver.gui.UpdateEvent;
import simplepushserver.utils.ZippyParser;

/**
 *
 * @author Filip
 */
public class CommandHandler{
    private SettingsHandler sh;
    private SimpleLogger logger;
    private Notifier notify;

    public CommandHandler(SettingsHandler sh, SimpleLogger logger, Notifier n) {
        this.sh = sh;
        this.notify = n;
        this.logger = logger;
    }

    public synchronized boolean runCommand(String command, String source){
        try{
            exec(command,source);
            return true;
        }catch(Exception e){
            e.printStackTrace();
            logger.log(source, "Exception" ,e.getMessage());
            return false;
        }
    }

    private void exec(String command, String source) throws Exception{
        if (command.startsWith("http://") || command.startsWith("https://")) {
            mouseClick(50, 2,false,true);
            if (command.contains("youtube.com")) {
                if (command.contains("fullscreen")) {
                    command.replace("watch?v=", "v/");
                    openURL(command);
                } else {
                    openURL(command);
                    runNir("win max ititle \"chrome\"");
                    sleep(5000);
                    mouseClick(1090, 560,false,true );
                }
            } else if (command.contains("soundcloud.com")) {
                openURL(command);
                sleep(500);
                runNir("win max ititle \"chrome\"");
                sleep(2000);
                mouseClick(85, 310, false, true);
            } else if (command.contains("zippyshare.com")) {
                //ArrayList<String> args = getUrlArgument(command);
                openURL(command);
                sleep(500);
                runNir("win max ititle \"chrome\"");
                sleep(2000);
                mouseClick(1280, 270, false, true);
                sleep(500);
                runNir("sendkeypress ctrl+w");
                String path = ZippyParser.getName(command);
                String filename = URLDecoder.decode(path, "utf8");
                if(filename !=null && Desktop.isDesktopSupported()){
                    balloon("Downloading from Zippyshare...\n"+filename);
                    File f = Folder.folderRootSearch(sh.getMediaFolders(), filename);
                    if (f == null){
                        f = Folder.search(sh.getMediaFolders(), filename.toLowerCase(),null);
                    }
                    if(f!=null){
                        Desktop.getDesktop().open(f);
                    }else{
                        notify.onNotification("Couldn't find file: "+filename+"\nPlease add your downloads-directory");
                    }
                }

            }else{
                openURL(command);
            }
            logger.log(source, "url", command);
        } else if (command.startsWith("spotify:")) {
            openURL(command);
            sleep(2500);
            if (command.contains("playlist:") || command.contains("album:") || command.contains("artist:")) {
                runNir("sendkeypress home");
            }
            runNir("sendkeypress enter");
            logger.log(source, "spotify", command);
        } else if (command.startsWith("spotifymusik:") || command.startsWith("play:")) {
            String name = command.split(":")[1].trim();
            File f = Folder.folderRootSearch(sh.getMediaFolders(), name);
            if (f == null) {
                f = Folder.search(sh.getMediaFolders(), name.toLowerCase(), notify);
            }
            if (f != null && f.exists()) {
                if (f.getName().endsWith(".wlx")) {
                    balloon("Live Mesh has not finnished sync on this file!");
                    speak("File not availble");
                } else {
                    if(sh.getMediaPlayPath()==null){
                        Desktop.getDesktop().open(f);
                    }else{
                        String s = "\"";
                        Runtime.getRuntime().exec(s+sh.getMediaPlayPath()+s+" "+s+f.getAbsolutePath()+s);
                        logger.log(source, "exec", s+sh.getMediaPlayPath()+s+" "+s+f.getAbsolutePath()+s);
                    }
                    balloon("Now playing " + f.getName());
                }
            } else {
                balloon("File " + name + " not found");
                speak("File " + name + " not found");
            }
            logger.log(source, "play", name+" ("+f.getAbsolutePath()+")");
        } else if (command.startsWith("enqueue:")){
            String name = command.split(":")[1].trim();
            File f = Folder.folderRootSearch(sh.getMediaFolders(), name);
            if (f == null) {
                f = Folder.search(sh.getMediaFolders(), name.toLowerCase(),notify);
            }
            if (f != null && f.exists()) {
                if (f.getName().endsWith(".wlx")) {
                    balloon("Live Mesh has not finnished sync on this file!");
                    speak("File not availble");
                } else if(sh.getMediaPlayPath()!=null){
                    String s = "\"";
                    String exec = s+sh.getMediaPlayPath()+s+" "+sh.getMediaEnqueueParam().replace("[filename]",s+f.getAbsolutePath()+s);
                    Runtime.getRuntime().exec(exec);
                    balloon(f.getName() + " enqueued");
                }else{
                    balloon("Enqueued command not supported using Desktop API");
                }
            } else {
                balloon("File not found");
            }
            logger.log(source, "enqueue", name +" ("+f.getAbsolutePath()+")");
        } else if (command.startsWith("google:")) {
            openURL("http://www.google.se/search?sourceid=chrome&ie=UTF-8"
                    + "&q=" + URLEncoder.encode(command.split(":")[1],"utf8"));
            logger.log(source, "google",command.split(":")[1].trim() );
        } else if (command.startsWith("volume:")) {
            if(logger.getLatest().getAction().contains("volume")){
                logger.log(source, "volume",command.split(":")[1].trim() );
            }
            setVolume(Integer.parseInt(command.split(":")[1].trim()));
        } else if (command.startsWith("open:")) {
            String name = command.substring(5).trim();
            if (name.contains("http://")) {
                ProgressListener pl = new ProgressListener() {
                    public void onUpdate(UpdateEvent ue) {
                        balloon("Downloading: " + Math.round(ue.getNewValue() * 1.0 / ue.getMax()) + "% done");
                        if (!ue.getMessage().isEmpty()) {
                            JOptionPane.showMessageDialog(null, ue.getMessage());
                        }
                    }
                };
                FileDownloader fd = new FileDownloader(name, new File(System.getenv("APPDATA")), pl);
                balloon("Downloading: " + name);
                fd.run();
                Desktop.getDesktop().open(fd.getTarget());
            } else {
                File f = Folder.folderRootSearch(sh.getMediaFolders(), name);
                if (f == null) {
                    f = Folder.search(sh.getMediaFolders(), name.toLowerCase(),notify);
                }
                if (f != null && f.exists()) {
                    if (f.getName().endsWith(".wlx")) {
                        balloon("Live Mesh has not finnished sync on this file!");
                        speak("File not availble");
                    } else {
                        Desktop.getDesktop().open(f);
                        balloon(f.getName() + " opened");
                    }
                } else {
                    balloon("File " + name + " not found");
                }
            }
        } else if (command.startsWith("kill:")) {
            runNir("killprocess " + command.split(":")[1].trim());
            logger.log(source, "kill",command.split(":")[1].trim() );
        } else if (command.startsWith("press:")) {
            runNir("sendkeypress " + command.split(":")[1].trim());
            logger.log(source, "press",command.split(":")[1].trim() );
        } else if (command.startsWith("speak:")) {
            speak(command.substring(command.indexOf(":") + 1));
            logger.log(source, "speak",command.split(":")[1].trim() );
        } else if (command.startsWith("balloon:")) {
            balloon(command.substring(command.indexOf(":") + 1));
            logger.log(source, "balloon",command.split(":")[1].trim() );
        } else if (command.startsWith("nircmd:")) {
            runNir(command.split(":")[1].trim());
            logger.log(source, "nircmd",command.split(":")[1].trim() );
        } else if (command.startsWith("cmd:")) {
            Runtime.getRuntime().exec(command.split(":")[1]);
            logger.log(source, "cmd",command.split(":")[1].trim() );
        } else if (command.startsWith("server:")) {
            if (command.split(":")[1].contains("kill")) {
                logger.log(source, "server",command.split(":")[1].trim() );
                System.exit(0);
            }
        } else if (command.startsWith("youtubeseek:")) {
            if (command.endsWith("pause")) {
                mouseClick(50, 2);
                logger.log(source, "youtubeseek",command.split(":")[1].trim() );
            }else{
                int per = Integer.parseInt(command.split(":")[1].trim());
                int screenSizeX = Toolkit.getDefaultToolkit().getScreenSize().width;
                int screenSizeY = Toolkit.getDefaultToolkit().getScreenSize().height;
                int x = (screenSizeX*per/100);
                runNir("setcursor "+(x+20)+" "+(screenSizeY-80)+" ");
                sleep(100);
                runNir("setcursor "+(x-20)+" "+(screenSizeY-80)+" ");
                sleep(100);
                mouseClick(x, screenSizeY-80,true,true);
                logger.log(source, "youtubeseek", per+" => "+x+":"+(screenSizeY-80));
            }
        } else if (command.startsWith("message:")) {
            NoneModalPopup ne = new NoneModalPopup(command.split(":")[1].trim(), "Message from " + source + " " + command.split(":")[1]);
            ne.start();
            logger.log(source, "message",command.split(":")[1].trim() );
        } else if (command.startsWith("ip:")) {
            runNir("monitor on");
            String text = source + " " + command.split(":")[1];
            speak(text);
            balloon(text);
            logger.log(source, "ip",command.split(":")[1].trim() );
        } else {
            NoneModalPopup ne = new NoneModalPopup("Unknown command: " + command, "Message from " + source);
            logger.log(source, "unknown",command );
            ne.start();
        }
    }

    private void balloon(String text) {
        notify.onNotification(text);
    }

    private void speak(String text) throws IOException {
        runNir("speak text \"" + text.trim() + "\" 0 100");
    }

    public void setVolume(int percent) throws IOException {
        balloon("Volume set to " + percent + "%");
        runNir("setsysvolume " + ((percent / 100.0) * 65536));
    }

    public void runNir(String value) throws IOException {
        if (sh.getNirCmdFile().exists()) {
            Runtime.getRuntime().exec(sh.getNirCmdFile().getAbsolutePath() + " " + value);
        } else {
            NoneModalPopup nmp = new NoneModalPopup("Could not locate your nircmd.exe, please consider corrent your nirpath in the settings", "NirCMD not found");
            nmp.start();
        }
    }
    static final String[] browsers = {"google-chrome", "firefox", "opera", "epiphany", "konqueror", "conkeror", "midori", "kazehakase", "mozilla"};

    public void openURL(String url) {
        if (Desktop.isDesktopSupported()) {
            try {
                Desktop.getDesktop().browse(new URI(url));
            } catch (Exception ex) {
                logger.log(CommandHandler.class.getName(), "url", ex.toString());
            }
        } else {
            String osName = System.getProperty("os.name");
            try {
                if (osName.startsWith("Mac OS")) {
                    Class.forName("com.apple.eio.FileManager").getDeclaredMethod(
                            "openURL", new Class[]{String.class}).invoke(null,
                            new Object[]{url});
                } else if (osName.startsWith("Windows")) {
                    Runtime.getRuntime().exec(
                            "rundll32 url.dll,FileProtocolHandler " + url);
                } else { //assume Unix or Linux
                    String browser = null;
                    for (String b : browsers) {
                        if (browser == null && Runtime.getRuntime().exec(new String[]{"which", b}).getInputStream().read() != -1) {
                            Runtime.getRuntime().exec(new String[]{browser = b, url});
                        }
                    }
                    if (browser == null) {
                        throw new Exception(Arrays.toString(browsers));
                    }
                }
            } catch (Exception e) {
                logger.log(CommandHandler.class.getName(), "Open URL", e.toString());
            }

        }
    }

    private void mouseClick(int x, int y) throws Exception { 
        mouseClick(x, y,true,true);
    } 
    private void mouseClick(int x, int y, boolean moveCursor, boolean left) throws Exception {
        runNir("setcursor "+x+" "+y+" ");
        sleep(500);
        if(left){runNir("sendmouse left click");}
        else{    runNir("sendmouse right click");}
    }
    private void sleep(long mills){
        try {
            Thread.sleep(mills);
        } catch (InterruptedException ex) {
            logger.log(CommandHandler.class.getName(), "Exception", ex.toString());
        }
    }

    private static ArrayList<String> getUrlArgument(String commands) {
        ArrayList<String> args = new ArrayList<String>();
        String[] a =  commands.split(" ");
        for(int i = 0; i < a.length; i++) {
            args.add(a[i]);
        }
        return args;
    }

}
